home *** CD-ROM | disk | FTP | other *** search
- /* --------------------------------------------------------------------------
- * Copyright 1992 by Forschungszentrum Informatik (FZI)
- *
- * You can use and distribute this software under the terms of the licence
- * you should have received along with this program.
- * If not or if you want additional information, write to
- * Forschungszentrum Informatik, "STONE", Haid-und-Neu-Strasse 10-14,
- * D-7500 Karlsruhe 1, Germany.
- * --------------------------------------------------------------------------
- */
- // **************************************************************************
- // Module psm Emil Sekerinski, Walter Zimmer
- //
- // **************************************************************************
- // persistent storage manager: implementation
- // **************************************************************************
-
- //#define LOCKD_CORRECT
- /*
- if defined
- then fcntl is used for container locking
- else flock is used for container locking
- fi
-
- As discussed in README.install, the default is "flock" (LOCKD_CORRECT not
- defined), because of a bug in the SunOS lock demon.
- The constant is set in the SOS Makefile when this file is compiled. See
- the macro USE_FCNTL there.
- */
-
- #include <sys/file.h>
- #include <osfcn.h>
- #include <libc.h>
- #include <errno.h>
- #include <sys/param.h>
- #include <string.h>
-
- // *** necessary (and only allowed) when using ATT 2.0 ***
- // #include <sys/time.h>
-
- #ifndef SEEK_SET
- #define SEEK_SET L_SET
- #define SEEK_CUR L_INCR
- #define SEEK_END L_XTND
- #endif
-
-
- #include "psm.h"
- #include "psm_err.h" // err_raise, err_SYS
- #include "trc_psm.h" // trace-module; numbers 11(H) -14(VL) + psm_CHECK
- #ifdef MONITOR
- #include "mon.h" // mon_Window,mon_create,mon_black,mon_white,mon_close
- #endif
- #include "knl_use.h" //
-
- // ******************* const definitions *********************************
-
- const UNUSED=0; // used for id's (value must be zero !)
- const UNDEF=-1; // used fur fileindex, bufferindex (also for fd in open())
- // for test, if object still exists or not (see list
- // free blocks)
-
- const SIZEOF_INT = 4; // if this is not valid => psm must be rewritten (!)
- const C=61; // container table size (max. number of open containers)
- const P=1024; // page size in bytes
- const int DEFAULT_BUFFERSIZE = 128; // def. size for paging buffer (can be
- // changed by SOSBUFFERSIZE/MONITOR)
- const N=(P/SIZEOF_INT-4)/2; // =#pagetable entries per page and version
- // =#container pages between pagetable pages
- const MAX_FREEBLOCK_LENGTH = P - 1 * SIZEOF_INT; // maximum for the length
- // of a free block
- const SWITCH_OFFSET = 0; // offset of switch in containerfile
- const err_msg ERR="container manager";
-
- const sos_Container TEMP_CONTAINER=sos_Container::make (0);
- const sos_Container ROOT_CONTAINER=sos_Container::make (1);
- const sos_Container UNUSED_CONTAINER=sos_Container::make (0xffffffff); //2^32-1
- const sos_Offset ROOT_OFFSET=P; // bytes 0..P-1 used for table of free blocks.
-
- // ******************* header variable definition **************************
-
- struct containerinfo
- {
- int id; // 1<=id<2^24-1 or id==UNUSED
- int status; // container status: READABLE or WRITEABLE or CHECKEDOUT
- int fd; // file descriptor of container file
- int sw; // upper/lower pagetable switch for current version
- int ubfreesize; // upper bound (approximative) of the size of all free blocks,
- // used for searching free blocks more efficiently
- int contpages; // number of container pages of current version
- int conttablesize; // size of the three subsequent arrays,must be multiple of N
- // ( >= contpages)
- int *bufferindex; // maps [0..contpages) to [0..B)+UNDEF
- int *fileindex; // maps [0..contpages) to [0..filepages)+UNDEF (page table)
- int *shadowed; // maps [0..contpages) to bool
- // (indicates, if shadow page exist)
- int filepages; // file pages occupied by the current container file
- // (upper bound for reference from fileindex to containerpage)
- int filetablesize; // size of freefilepage array ( >= filepages )
- int *freefilepage; // maps [0..filepages) to bool, i.e., indicates the free
- // pages in the container file
- int freefilepage_index; // index to make search for next freefilepage more
- // efficient; points to last found empty page (in
- // the beginning => -1)
- #ifdef MONITOR
- mon_Window win;
- #endif
- };
- static containerinfo containertable[C]; // `hash` table for container entries
-
- static int B; // number of pages in buffer, 1 <= B <= Bmax
- struct bufinfo // info for each page in buf[0..B)
- {
- int id, page; // backward reference to container id and container page,
- // used for page replacement: id==UNUSED || (id==
- // containertable[?].id && 0<=page<containertable[?].contpages)
- int referenced; // used for page replacement (second chance algorithm)
- int modified; // indicates that page has to be written on commit
- };
-
- static int buftable_index = 0; // buffer table index : used for page replacement
-
- typedef char PAGE[P];
-
- static PAGE *buf; // internal buffer for paging
- static bufinfo *buftable; // table of infos for each page of the buffer
-
-
- #ifdef MONITOR
- static int monactivated;
- #endif
-
- // err_buffer is used for variable error messages
- // current use only in : lookupcontainer
- static char err_buffer[150];
-
- static struct initialize
- { // calls automatically psm_initialize when main program starts, because
- // initialize() is constructor of struct initialize (standard trick)
-
- initialize() {psm_initialize();}
- } dummy;
-
-
- //-----------------------------------------------------------------------------
-
- void psm_initialize()
- {
- B = DEFAULT_BUFFERSIZE; // normal value of B if not monitoring
- // && SOSBUFFERSIZE not set
-
- char* bufsize = getenv("SOSBUFFERSIZE");
- if (bufsize != 0) // SOSBUFFERSIZE is set
- {
- sscanf(bufsize,"%d",&B);
- if (B <= 0)
- B = DEFAULT_BUFFERSIZE;
- }
-
- #ifdef MONITOR
- monactivated = FALSE;
- char* e = getenv("SOSMONITOR");
- if (e != 0)
- {
- sscanf(e,"%d",&B);
- if (B > 0)
- {
- mon_initialize();
- monactivated = TRUE;
- }
- else
- B = DEFAULT_BUFFERSIZE;
- }
- #endif
-
- #if BOOT
- srandom(1);
- #else
- timeval tp;
- gettimeofday(&tp,0);
- srandom((int)tp.tv_sec);
- #endif
-
- buftable = new bufinfo [B]; // allocation of buffers
- buf = new PAGE [B];
-
- int i,j; // initialization of buffers and tables
- for (i = 0; i < C; i++) containertable[i].id = UNUSED;
- for (i = 0; i < B; i++) buftable[i].id = UNUSED;
- for (i = 0; i < B; i++)
- for (j = 0; j < P; j++) buf[i][j] = UNUSED;
-
- }
-
- //--------------------------------------------------------------------------
- // auxiliary functions ( and inline functions )
- //--------------------------------------------------------------------------
-
- inline int min(int a, int b)
- {
- return (a < b ? a : b);
- }
-
- inline int max(int a, int b)
- {
- return (a > b ? a : b);
- }
-
- inline int offrounded_pagenumber(int size) // returns floor(size/P)
- {
- return (int)(size / P);
- }
-
- inline int uprounded_pagenumber(int size) // returns ceil(size/P)
- {
- return (int)((size + P - 1) / P);
- }
-
- inline int N_upround(int nr) // returns the next multiple of N
- {
- return ((nr + N - 1) / N) * N;
- }
-
- //--------------------------------------------------------------------------
-
- inline int pagetable_offset(int page, int sw)
- {
- // return offset of pagetable in containerfile, which contains entry for `page`.
- // addition of offsets for
- // (1) page of pagetable
- // (2) offset inside of this page (old or new pagetable)
-
- return (int)( (page/N) * (N+1) * P + (sw ? 4 : 4 + N) * SIZEOF_INT);
- }
- //--------------------------------------------------------------------------
-
- inline int contpages_offset(int sw)
- {
- return (int)( (sw ? 1 : 2) * SIZEOF_INT );
- }
- //--------------------------------------------------------------------------
- //-------------------- end of inline functions -------------------------
- //--------------------------------------------------------------------------
-
-
-
- static unsigned used_pages(containerinfo &ci)
- {
- // returns number of occupied pages (referenced from fileindex)
- // containerfile is normally larger than necessary because of unused
- // pages and shadowed pages (if container is open)
-
- unsigned used_pags = 0;
- for (int p = 0; p < ci.contpages; p++)
- if (ci.fileindex[p] != UNDEF) used_pags++;
- return used_pags;
- }
-
- //--------------------------------------------------------------------------
-
- static unsigned free_pages(containerinfo &ci)
- {
- // returns number of free places (UNDEF) in fileindex
-
- return (ci.contpages - used_pages(ci));
- }
-
- //------------------------------------------------------------------------------
-
- static int lock(int fd, sos_Access_mode am, sos_Sync_mode sm)
- {
- T_PROC ("psm::lock");
- TT (psm_H, T_ENTER; TI((int)fd);TI((int)am);TI((int)sm));
- /*
- This version of lock uses the nfs locking mechanism via fcntl. Due to
- bugs in the implementation, it may cause in a network of sun3 and sun4
- stations the file server to crash !
- */
-
- #ifdef LOCKD_CORRECT
-
- struct flock fl;
- fl.l_type = (am == READING ? F_RDLCK : F_WRLCK);
- fl.l_whence = 0; //starting offset = start of file
- fl.l_start = 0; //relative_offset=0
- fl.l_len = 0; //to end of file
- int cmd = (sm == TESTING ? F_SETLK : F_SETLKW);
- return fcntl(fd, cmd, (int)&fl) != -1;
-
- /*
- This version of lock sets the locks via flock. Locks obtained through
- flock are only known to the system on which they are placed. Thus
- inconsistencies may arise if the file is accessed via nfs from different
- stations.
- */
-
- #else
-
- int access = (am == READING ? LOCK_SH : LOCK_EX);
- int sync = (sm == WAITING ? 0 : LOCK_NB);
- TT (psm_H, T_LEAVE);
- return flock(fd, access | sync) == 0;
-
- #endif LOCKD_CORRECT
- }
-
- //------------------------------------------------------------------------------
-
- inline containerinfo* containertable_pos(int id)
- {
- // returns containertable entry with key `id` (id == UNUSED == 0
- // possible, see newcontainer), if container with `id` is opened, else UNDEF
-
- containerinfo *start, *probe;
- probe =
- start = &containertable[id % C];
- // in most cases a good starting point (see newcontainer)
- do
- { if (probe->id == id) return probe;
- probe = (probe == containertable) ? &containertable[C-1]
- : -- probe;
- } while (probe != start);
-
- return (containerinfo *)UNDEF;
- }
-
- //------------------------------------------------------------------------------
-
-
- inline int container_is_open(int id)
- {
- // returns TRUE, if its status equals READABLE, WRITEABLE, CHECKEDOUT
- // or DESTROYED, i.e. , if 'id' is in containertable
-
- return (containertable_pos(id) != (containerinfo *)UNDEF);
- }
-
- //------------------------------------------------------------------------------
-
- static containerinfo &newcontainer(int id)
- {
- containerinfo *start, *probe;
- probe =
- start = &containertable[id % C];
- // in most cases a good starting point (see containertable_pos)
- do
- { if (probe->id == UNUSED) return *probe;
- probe = (probe == containertable) ? &containertable[C-1]
- : -- probe;
- } while (probe != start);
-
- err_raise(err_SYS,err_PSM_CONTAINER_TABLE_FULL,ERR,FALSE);
- return containertable[0]; // never reached! - only to avoid warnings
- }
-
- //------------------------------------------------------------------------------
-
- static containerinfo &lookupcontainer (int id,
- int open_on_read,
- int check_if_writing,
- int destroyed_permitted = FALSE)
- {
- // gives back the index in the containertable
- // if container not in the containertable and open_on_read
- // -> implicit open if possible
- // check_if_writing to control, whether the user has write permission
- // destroyed_permitted only is TRUE for operations, for which
- // operations on destroyed containers are allowed
- // (destroy, close, commit, reset ; status, exists, object_exists)
-
- containerinfo *ct = containertable_pos(id);
-
- if (ct == (containerinfo *)UNDEF)
- if (open_on_read)
- if (sos_Container::make(id).open(READING,WAITING)==OPENED)
- return lookupcontainer(id,FALSE,FALSE);
- else
- { // 36 characters, 20 reserved for %d's, 70 for %s <= 150 characters
- sprintf(err_buffer,"cannot open container %d\n\tUnix error %d : %.70s", id, errno,
- (0 <= errno && errno < sys_nerr) ? sys_errlist[errno]
- : "***");
- err_raise(err_SYS,err_buffer,ERR,FALSE);
- }
- else err_raise(err_SYS,err_PSM_UNOPENED_CONTAINER,ERR,FALSE);
- else
- if (ct->status == DESTROYED)
- if (destroyed_permitted)
- return *ct; // avoid check_if_writing
- else
- err_raise(err_SYS,err_PSM_DESTROYED_CONTAINER,ERR,FALSE);
-
- if (check_if_writing && ct->status != WRITEABLE)
- err_raise(err_SYS,err_PSM_NONWRITEABLE_CONTAINER,ERR,FALSE);
- return *ct;
- }
-
- //------------------------------------------------------------------------------
-
- static void extendtable(int *&tab, int size, int newsize)
- {
- int *newtab = new int[newsize];
- for (int i = 0; i < size; i++) newtab[i] = tab[i];
- for (i = size; i < newsize; i++) newtab[i] = 0; // initialize with zero
- delete tab;
- tab = newtab;
- }
-
- //------------------------------------------------------------------------------
-
- static void calculatefreefilepages(containerinfo &ci)
- {
- // calculates ci.freefilepage, ci.filepages and clears ci.shadowed
- // used only in readpagetable/writepagetable => ci.shadowed[]=FALSE
-
- for (int p = 0; p < ci.filetablesize; p++) ci.freefilepage[p] = TRUE;
- ci.filepages = 0;
- for (p = 0; p < ci.contpages; p++)
- { if (ci.fileindex[p] != UNDEF)
- { ci.freefilepage[ci.fileindex[p]] = FALSE;
- ci.filepages = max (ci.filepages,ci.fileindex[p] + 1);
- }
- ci.shadowed[p] = FALSE;
- }
- }
-
-
- //------------------------------------------------------------------------------
-
- static int findfreefilepage(containerinfo &ci)
- {
- // returns number of first free file page, mark it as used
- // and increment (if necessary) ci.filepages
-
- if (ci.filepages > 0)
- ci.freefilepage_index = (ci.freefilepage_index + 1) % ci.filepages;
- else
- ci.freefilepage_index = 0;
-
- // "+1" for next possibly empty filepage; "% ci.filepages"
- // because in writepagetable (in commit) the container can be truncated
- // (decrease ci.filepages) and the ci.freefilepage_index can so point
- // to a location outside the container area
-
- int p = 0;
- while (p < ci.filepages && ! ci.freefilepage[ci.freefilepage_index])
- { p++;
- ci.freefilepage_index = (ci.freefilepage_index + 1) % ci.filepages;
- }
-
- if (p == ci.filepages) // no free page found (else freefilepage_index
- // points to a free page)
- { if (ci.filetablesize == p)
- { extendtable(ci.freefilepage,p,2*p);
- ci.filetablesize *= 2;
- }
- ci.filepages++;
- ci.freefilepage_index = p;
- }
-
- ci.freefilepage[ci.freefilepage_index] = FALSE;
- return ci.freefilepage_index; }
-
- //------------------------------------------------------------------------------
-
- static int fileposition(int filepage)
- {
- // the term filepage/N+1 adjusts for the pages of the
- // "page table" scattered in the container file
- // pages ( = filepage) + pages of pagetable( = filepage/N)
- // + rootoffset (1 = table of free blocks)
-
- return (filepage + filepage/N + 1) * P;
- }
-
- //------------------------------------------------------------------------------
-
- static void readpage(containerinfo &ci, int contpage, int bufpage)
- {
- int filepage = ci.fileindex[contpage];
- if (filepage == UNDEF) err_raise(err_SYS,err_PSM_WRONG_OFFSET,ERR,FALSE);
- lseek(ci.fd, fileposition(filepage), SEEK_SET);
- read(ci.fd, buf[bufpage], P);
- }
-
- //------------------------------------------------------------------------------
-
- static void writepage(containerinfo &ci, int contpage, int bufpage)
- {
- int &filepage = ci.fileindex[contpage];
- if (filepage == UNDEF) err_raise(err_SYS,err_PSM_WRITEPAGE,ERR,FALSE);
- if ( ! ci.shadowed[contpage])
- { filepage = findfreefilepage(ci);
- ci.shadowed[contpage] = TRUE;
- }
- lseek(ci.fd, fileposition(filepage), SEEK_SET);
- write(ci.fd, buf[bufpage], P);
- }
-
- //------------------------------------------------------------------------------
-
- static int preemptpage(int id, int contpage)
- {
- // choose buffer page according to the second chance algorithm,
- // write chosen page back to container file if necessary and
- // mark chosen buffer page as used for 'contpage' of container 'id'.
-
- while (buftable[buftable_index].referenced)
- {
- buftable[buftable_index].referenced = FALSE;
- buftable_index =(buftable_index + 1) % B;
- }
- if (buftable[buftable_index].id != UNUSED)
- { containerinfo &ci = lookupcontainer(buftable[buftable_index].id,FALSE,FALSE);
- if (buftable[buftable_index].modified)
- writepage(ci,buftable[buftable_index].page,buftable_index);
- ci.bufferindex[buftable[buftable_index].page] = UNDEF;
- #ifdef MONITOR
- if (monactivated) mon_white(ci.win,buftable[buftable_index].page);
- #endif
- }
- buftable[buftable_index].id = id;
- buftable[buftable_index].page = contpage;
- buftable[buftable_index].modified = FALSE;
- int result = buftable_index;
- buftable_index = (buftable_index + 1) % B;
- return result; }
-
- //------------------------------------------------------------------------------
-
- static int lookuppage(containerinfo &ci, int contpage)
- {
- // return index of buffer page of container ci's contpage
- // if contpage not already in buffer, read it from the container file
- // by swapping it with another container page if necessary.
-
- if (contpage >= ci.contpages) err_raise(err_SYS,err_PSM_WRONG_OFFSET,ERR,FALSE);
- int &bufpage = ci.bufferindex[contpage];
- if (bufpage == UNDEF)
- { bufpage = preemptpage(ci.id,contpage);
- #ifdef MONITOR
- if (monactivated) mon_black(ci.win,contpage);
- #endif
- readpage(ci,contpage,bufpage);
- }
- buftable[bufpage].referenced = TRUE;
- return bufpage;
- }
-
- //------------------------------------------------------------------------------
-
- static int readint(containerinfo &ci, sos_Offset o)
- {
- // pre: o%P+SIZEOF_INT<=P, i.e. data does not cross page boundary
-
- return * (int*) &buf[lookuppage(ci,o/P)][o%P];
- }
-
- //------------------------------------------------------------------------------
-
- static void writeint(containerinfo &ci, sos_Offset o, int a)
- {
- // pre: o%P+SIZEOF_INT<=P, i.e. data does not cross page boundary
-
- int bufpage = lookuppage(ci,o/P);
- * (int*) &buf[bufpage][o%P] = a;
- buftable[bufpage].modified = TRUE;
- }
-
- //------------------------------------------------------------------------------
-
- static void readfrompage(containerinfo &ci, int page, int disp, int len, void *data)
- {
- // pre: disp+len<=P, i.e. data does not cross page boundary
-
- bcopy(&buf[lookuppage(ci,page)][disp], data, len);
- }
-
- //------------------------------------------------------------------------------
-
- static void writetopage(containerinfo &ci, int page, int disp, int len, void *data)
- {
- // pre: disp+len<=P, i.e. data does not cross page boundary
-
- int bufpage = lookuppage(ci,page);
- bcopy(data, &buf[bufpage][disp], len);
- buftable[bufpage].modified = TRUE;
- }
-
- //------------------------------------------------------------------------------
-
- static void readpagetable(containerinfo &ci)
- {
- // read ci.sw, ci.contpages, ci.fileindex from container file,
- // calculate ci.freefilepage, ci.filepages,
- // clear ci.shadowed and initialize ci.ubfreesize
-
- if (lseek(ci.fd,0,SEEK_END) == 0) // container file empty
- { ci.sw = 0;
- ci.contpages = 0;
- }
- else // read ci.sw, ci.contpages, and ci.fileindex from file
- { lseek(ci.fd,SWITCH_OFFSET,SEEK_SET); // ci.sw
- read(ci.fd,&ci.sw,SIZEOF_INT);
- lseek(ci.fd,contpages_offset(ci.sw),SEEK_SET); //ci.contpages
- read(ci.fd,&ci.contpages,SIZEOF_INT);
- for (int i = 0; i < ci.contpages; i += N)
- { lseek(ci.fd, pagetable_offset(i,ci.sw), SEEK_SET);
- read(ci.fd, &ci.fileindex[i], N * SIZEOF_INT);
- }
- }
- calculatefreefilepages(ci);
- ci.ubfreesize = MAX_FREEBLOCK_LENGTH; }
-
- //------------------------------------------------------------------------------
-
- static void writepagetable(containerinfo &ci)
- {
- // toggle ci.sw and write ci.contpages, ci.fileindex to container file
- // recalculate ci.freefilepage and clear ci.shadowed.
-
- ci.sw = !ci.sw;
- lseek(ci.fd, contpages_offset(ci.sw), SEEK_SET);
- write(ci.fd, &ci.contpages, SIZEOF_INT);
- for (int i = 0; i < ci.contpages; i += N)
- { lseek(ci.fd, pagetable_offset(i,ci.sw), SEEK_SET);
- write(ci.fd, &ci.fileindex[i], N * SIZEOF_INT);
- }
- fsync(ci.fd);
- lseek(ci.fd, 0, SEEK_SET);
- write(ci.fd, &ci.sw, SIZEOF_INT);
- calculatefreefilepages(ci);
- ftruncate(ci.fd,fileposition(ci.filepages));
- }
-
- //------------------------------------------------------------------------------
-
- static char* containerpath(int id) // return pointer to path of container id
- {
- static char n[MAXPATHLEN];
- char* e = getenv("SOSCONTAINER");
- if (e != 0)
- if (strlen(e) < MAXPATHLEN-12) // 12=length of containerfile-name
- {
- strcpy(n,e);
- strcat(n,"/");
- sprintf(n + strlen(n),"%d",id);
- return n;
- }
- else err_raise(err_SYS,err_PSM_PATH_TOO_LONG,ERR,FALSE);
- else err_raise(err_SYS,err_NO_CONTAINER_PATH,ERR,FALSE);
- }
-
- //------------------------------------------------------------------------------
-
- static void entercontainer(int id, int fd, sos_Access_mode a)
- {
- // makes the necessary initializations for the containerinfo ci
- // when opening a new container
-
- fcntl(fd,F_SETFD,1); // close on exec
- containerinfo &ci = newcontainer(id);
- ci.id = id;
- ci.status = (sos_Container_status) a;
- ci.fd = fd;
- int realpages = uprounded_pagenumber(int(lseek(fd,0,SEEK_END)));
- // total number of file pages
-
- int tablesize = (realpages == 0) ? N
- : N_upround(realpages);
- // realpages rounded up to a positive multiple of N
-
- ci.conttablesize = tablesize;
- ci.filetablesize = tablesize;
- ci.fileindex = new int[tablesize];
- ci.shadowed = new int[tablesize];
- ci.freefilepage = new int[tablesize];
- ci.freefilepage_index = -1; // = no freefilepage found
- readpagetable(ci);
- ci.bufferindex = new int[tablesize];
- for (int p = 0; p < ci.contpages; p++) ci.bufferindex[p] = UNDEF;
- #ifdef MONITOR
- if (monactivated)
- {
- ci.win = mon_create(ci.id, ci.contpages);
- char *title;
- if (ci.contpages <= 1) title = strdup ("<new>");
- else
- {
- sos_Object o = sos_Container::make(ci.id).root_object();
- if (o.isa (sos_Named_type))
- title = sos_Named::make(o).get_name().make_Cstring();
- else {
- title = new char [12];
- sprintf(title,"%d",ci.id); }
- }
- mon_open(ci.win,a,title);
- delete title;
- }
- #endif
- }
-
- //------------------------------------------------------------------------------
-
- static void removecontainer(containerinfo &ci)
- {
- for (int i = 0; i < B; i++)
- if (buftable[i].id == ci.id)
- {
- buftable[i].id = UNUSED;
- #ifdef MONITOR
- if (monactivated) mon_white(ci.win,buftable[i].page);
- #endif
- }
- ci.id = UNUSED;
- delete ci.bufferindex;
- delete ci.fileindex;
- delete ci.shadowed;
- delete ci.freefilepage;
- close(ci.fd); //also unlocks file
- #ifdef MONITOR
- if (monactivated) mon_close(ci.win);
- #endif
- }
-
- //------------------------------------------------------------------------------
-
- static void commitcontainer(containerinfo &ci)
- {
- for (int p = 0; p < ci.contpages; p++)
- if (ci.bufferindex[p] != UNDEF && buftable[ci.bufferindex[p]].modified) {
- writepage(ci,p,ci.bufferindex[p]);
- buftable[ci.bufferindex[p]].modified = FALSE; }
- writepagetable(ci);
- }
-
- //------------------------------------------------------------------------------
-
- static void resetcontainer(containerinfo &ci)
- {
- if (ci.status == DESTROYED) ci.status = WRITEABLE;
- // a container could only be destroyed with status WRITEABLE
-
- for (int p = 0; p < ci.contpages; p++) // deallocate modified pages in buffer
- if (ci.bufferindex[p] != UNDEF && buftable[ci.bufferindex[p]].modified)
- {
- buftable[ci.bufferindex[p]].id=UNUSED;
- ci.bufferindex[p] = UNDEF;
- }
- readpagetable(ci); // readpagetable from containerfile
- }
-
- //------------------------------------------------------------------------------
-
- static void squeezecontainer(containerinfo &ci)
- {
- int u = used_pages(ci);
- for (int p = 0; p < ci.contpages; p++)
- if (ci.fileindex[p] >= u) // pre : UNDEF < 0
- buftable[lookuppage(ci,p)].modified = TRUE;
-
- ci.freefilepage_index = -1; // reset freefilepage_index
-
- // if it doesn't equal -1 then it happens this in the following commit:
- // the modified pages could be written (see commit -> findfreefilepage ->...)
- // to free pages at the end of the container file
- // => the container will not be truncated (or only parts of) after the commit
- }
-
- //------------------------------------------------------------------------------
-
- static unsigned allocatepages(containerinfo &ci, int n)
- {
- // returns offset of n consecutive free pages and marks them as used
-
- int p = 0, f = 0, s = 0;
- while (s < n && p < ci.contpages)
- if (ci.fileindex[p] == UNDEF) {s++; p++;}
- else {s = 0; p++; f = p;}
- if (s < n)
- {
- ci.contpages += n - s;
- if (ci.conttablesize < ci.contpages)
- { int newsize = N_upround (ci.contpages);
- extendtable(ci.bufferindex, ci.conttablesize, newsize);
- extendtable(ci.fileindex, ci.conttablesize, newsize);
- extendtable(ci.shadowed, ci.conttablesize, newsize);
- ci.conttablesize = newsize;
- }
- }
- for (s = 0; s < n; s++)
- { ci.fileindex[f+s] = findfreefilepage(ci);
- ci.shadowed[f+s] = TRUE;
- ci.bufferindex[f+s] = preemptpage(ci.id, f+s);
- #ifdef MONITOR
- if (monactivated) mon_black(ci.win,f+s);
- #endif
- buftable[ci.bufferindex[f+s]].modified = TRUE;
- bzero(buf[ci.bufferindex[f+s]], P);
- }
- return f * P;
- }
-
- //------------------------------------------------------------------------------
-
- static void deallocatepages(containerinfo &ci, int p, int n)
- {
- // mark n consecutive pages starting with page p as unused
-
- while (n > 0)
- {
- if (ci.shadowed[p])
- { ci.freefilepage[ci.fileindex[p]] = TRUE;
- // only to shadowed pages because of a possible reset to the container
- ci.shadowed[p] = FALSE;
- }
- ci.fileindex[p] = UNDEF;
- if (ci.bufferindex[p] != UNDEF)
- {
- buftable[ci.bufferindex[p]].id = UNUSED;
- ci.bufferindex[p] = UNDEF;
- }
- n--; p++;
- }
- }
-
- //------------------------------------------------------------------------------
-
- static unsigned size_of_free_blocks(containerinfo &ci)
- {
- int sum = 0;
- for (int sz = 4; sz <= MAX_FREEBLOCK_LENGTH; sz += 4)
- { int o = sz;
- while (readint(ci,o) != 0) { // sum all free blocks of size sz
- sum += sz; o = readint(ci,o); }
- }
- return sum;
- }
-
- //------------------------------------------------------------------------------
-
- static unsigned freesize(containerinfo &ci)
- {
- // free size of logical container, not of container file
-
- return (free_pages(ci) * P + size_of_free_blocks(ci));
- }
-
- //------------------------------------------------------------------------------
-
- #ifndef NO_TT
-
- // check_freelists checks for a block (given by containerinfo, start and length
- // of the block), if it overlaps with a block in the freelist of the container
- // (the freelist contains previous deallocated blocks).
- // if (_psm_checked_cnt == 0) check all containers
- // else check only _psm_checked_cnt
-
- const sos_Container _psm_checked_cnt = sos_Container::make (0);
-
- void check_freelists (containerinfo &ci, int start, int length)
- { if ( ( _psm_checked_cnt == 0 || _psm_checked_cnt == ci.id)
- && ci.id != 0)
- {
- for (int size = 4; size <= MAX_FREEBLOCK_LENGTH; size += 4)
- { // iterate over lists of different size
-
- int offset = readint(ci,size);
- while (offset != 0)
- {
- if ((start >= offset && start < (offset + size))
- || (start < offset && (start + length) > offset))
- err_raise(err_SYS,err_PSM_FREELIST_CHECK_FAILED,ERR,FALSE);
- offset = readint(ci,offset); // next list_element
- }
- }
- }
- }
-
- #endif NO_TT
-
- // ******************************************************************************
- // functions of class sos_Container
- // ******************************************************************************
- /*
- static void sos_Container::compress()
- {
- // compress (or merges) blocks of the freelist
-
- containerinfo &ci = lookupcontainer(id,FALSE,FALSE);
-
- int *A = new int[ci.contpages]; // initialization of A
- for (int i = 0; i < ci.contpages; i++) A[i] = UNDEF;
-
-
- for (int size = 4; size <= MAX_FREEBLOCK_LENGTH; size += 4)
- { // Iterate over blocks of the freelist & destroy freelists (!)
-
- int current_offset1 = readint(ci,size);
- // element which will be inserted in list 2
- writeint(ci,size,UNDEF); // listheader is destroyed
-
- while (current_offset1 != 0)
- { next_offset1 = readint(ci,current_offset1);
-
- current_offset2 = A[i]; // offset of current element in list 2
- last_offset2 = 0; // offset of last element in list 2
-
- while (current_offset1 > current_offset2 && current_offset2 != 0 )
- { // find right place in list2 to insert
- last_offset2 = current_offset2;
- current_offset2 = readint(ci, current_offset2);
- }
-
- if (current_offset2 == A[i] // insert at list header (list can be empty)
- { A[i] = current_offset1;
- writeint(ci, current_offset1, current_offset2);
- }
- else
- { if (last_offset == 0)
- err_raise(err_SYS,err_PSM_COMPRESS,ERR,FALSE);
- writeint(ci, last_offset2, current_offset1);
- writeint(ci, current_offset1, current_offset2);
- }
-
- current_offset1 = next_offset1; // next list element
- }
- }
-
- // Sort & Merge new lists
-
- for ( i = 0; i < ci.contpages; i++)
- { if (A[i] == UNDEF)
- if (fileindex[i] == UNDEF)
- newfileindex[i] = UNDEF; // page 'i' is not allocated (used)
- else
- newfileindex[i] = fileindex[i]; // page contains no free blocks
- else
- if (fileindex[i] == UNDEF)
- err_raise(err_SYS,err_PSM_COMPRESS,ERR,FALSE);
- // page 'i' is not allocated but contains free blocks
- else
- merge_blocks(i);
- }
-
- // ___ merge blocks
-
- void merge_blocks()
- {
- offset
-
-
- ??? Problem, da ich Groesse der Bloecke nicht abgspeichert habe
-
- => bauche doch explizite andere Datenstruktur (entweder Liste oder Baum)
- in GNU-Bibliotheken ?
-
-
-
-
- delete A;
-
- */
- //------------------------------------------------------------------------------
-
- sos_Container sos_Container::create()
- {
- T_PROC ("sos_Container::create");
- TT (psm_H, T_ENTER);
-
- int id, fd;
- do
- {
- id = (int)(random()%0xfffffd)+2; // 1<id<2^24-1
- fd = ::open(containerpath(id),O_RDWR | O_CREAT | O_EXCL,0664);
- // owner:rw, group:r others:r
- }
- while (fd == UNDEF && errno == EEXIST);
-
- if (fd == UNDEF) err_raise(err_SYS,err_PSM_CREATE_FAILED,ERR,FALSE);
- lock(fd,WRITING,WAITING);
- entercontainer(id,fd,WRITING);
-
- TT (psm_H, T_LEAVE; TI((int)id));
- return sos_Container::make (id);
- }
- //------------------------------------------------------------------------------
-
- sos_Container_status sos_Container::status() const
- {
- // return status of an opened container or UNAVAILABLE, if not opened
-
- T_PROC ("sos_Container::status");
- TT (psm_H, T_ENTER; TI(id));
-
- if (id == 0) err_raise(err_SYS,err_PSM_STATUS_ON_TEMP, ERR,FALSE);
- containerinfo *ct = containertable_pos(id);
-
- sos_Container_status result
- = (ct == (containerinfo *)UNDEF) ? (sos_Container_status) UNAVAILABLE
- : (sos_Container_status) ct->status;
-
- TT (psm_H, T_LEAVE; TI(result));
- return result;
- }
-
-
- //------------------------------------------------------------------------------
-
- sos_Open_result sos_Container::open(sos_Access_mode a, sos_Sync_mode s) const
- {
- T_PROC ("sos_Container::open");
- TT (psm_H, T_ENTER; TI(id); TI((int)a); TI((int)s));
-
- if (id == 0) err_raise(err_SYS,err_PSM_OPEN_ON_TEMP, ERR,FALSE);
- if ( ! container_is_open(id))
- { int fd = ::open(containerpath(id),O_RDWR,0644); // O_RDWR for upgrading
- if (fd == UNDEF)
- { TT (psm_H, T_LEAVE; TI((int)UNACCESSIBLE));
- return UNACCESSIBLE;
- }
- if (!lock(fd,a,s))
- { ::close(fd);
- TT (psm_H, T_LEAVE; TI((int)LOCKED));
- return LOCKED;
- }
- entercontainer(id,fd,a);
- }
- else
- { containerinfo &ci = lookupcontainer(id,FALSE,FALSE);
- if (ci.status == READABLE && a == WRITING)
- { if (!lock(ci.fd,WRITING,s))
- {
- // attention if using flock: if exclusive flock fails and
- // you had an shared flock before then no lock exits
- // afterwards. Because of that one tries to set again a (new)
- // shared lock. If this fails -> errormessage
- // very seldom because between exclusive lock and shared
- // lock (milliseconds) the following must happen:
- // the other users with a shared lock must unset their
- // locks and someone must set an exclusive lock
-
- if (!lock(ci.fd,READING,TESTING))
- err_raise(err_SYS,err_PSM_LOST_ALL_LOCKS, ERR,FALSE);
- TT (psm_H, T_LEAVE; TI((int)LOCKED));
- return LOCKED;
- }
- ci.status = WRITEABLE;
- }
- }
-
- TT (psm_H, T_LEAVE; TI((int)OPENED));
- return OPENED;
- }
-
- //------------------------------------------------------------------------------
-
- sos_Open_result sos_Container::access(sos_Access_mode a, sos_Sync_mode s) const
- {
- // only used for upgrading/downgrading
- // implicit commit if downgrading
-
- T_PROC ("sos_Container::access");
- TT (psm_H, T_ENTER; TI(id); TI((int)a); TI((int)s));
-
- if (id == 0) err_raise(err_SYS,err_PSM_ACCESS_ON_TEMP, ERR,FALSE);
- if ( ! container_is_open(id)) err_raise(err_SYS,err_PSM_NO_ACCESS,ERR,FALSE);
- containerinfo &ci = lookupcontainer(id,FALSE,FALSE);
- if (ci.status == WRITEABLE) commitcontainer(ci);
- if (!lock(ci.fd,a,s))
- // attention if using flock (see 20 lines above) if upgrading fails
- // you have no lock anymore therefore try again a shared lock
- { if (!lock(ci.fd,READING,TESTING))
- err_raise(err_SYS,err_PSM_LOST_ALL_LOCKS, ERR,FALSE);
- else if (ci.status == READABLE)
- { TT(psm_H, T_LEAVE; TI((int)LOCKED));
- return LOCKED;
- }
- }
- ci.status = (sos_Container_status) a;
-
- TT (psm_H, T_LEAVE; TI((int)OPENED));
- return OPENED;
- }
-
- //------------------------------------------------------------------------------
-
- void sos_Container::close() const
- {
-
- T_PROC ("sos_Container::close");
- TT (psm_H, T_ENTER; TI(id));
-
- if (id == 0) err_raise(err_SYS,err_PSM_CLOSE_ON_TEMP, ERR,FALSE);
- containerinfo &ci = lookupcontainer(id,FALSE,FALSE,TRUE);
- if (ci.status == WRITEABLE) commitcontainer(ci);
- if (ci.status == DESTROYED) unlink(containerpath(id));
- removecontainer(ci);
-
- TT (psm_H, T_LEAVE);
- }
-
- //------------------------------------------------------------------------------
-
- void sos_Container::destroy() const
- {
-
- T_PROC ("sos_Container::destroy");
- TT (psm_H, T_ENTER; TI(id));
-
- if (id == 0) err_raise(err_SYS,err_PSM_DESTROY_ON_TEMP, ERR,FALSE);
- containerinfo &ci = lookupcontainer(id,FALSE,TRUE,TRUE);
- if (ci.status == CHECKEDOUT) // WRITEABLE and CHECKEDOUT differ only
- // in this operation
- err_raise(err_SYS,err_PSM_DESTROY_DURING_CHECKOUT,ERR,FALSE);
-
- if (ci.status != DESTROYED)
- { clear(); // clear is not necessary, but saves space
- // (clear is only called for the first destroy)
- ci.status = DESTROYED;
- }
- TT (psm_H, T_LEAVE);
- }
-
- //------------------------------------------------------------------------------
-
- void sos_Container::commit() const
- {
- T_PROC ("sos_Container::commit");
- TT (psm_H, T_ENTER; TI(id));
-
- if (id == 0) err_raise(err_SYS,err_PSM_COMMIT_ON_TEMP, ERR,FALSE);
- containerinfo& ci = lookupcontainer(id,FALSE,TRUE,TRUE);
- if (ci.status == DESTROYED)
- {
- unlink(containerpath(id));
- removecontainer(ci);
- }
- else
- commitcontainer(ci);
-
- TT (psm_H, T_LEAVE);
- }
-
- //------------------------------------------------------------------------------
-
- void sos_Container::reset() const
- {
- T_PROC ("sos_Container::reset");
- TT (psm_H, T_ENTER; TI(id));
-
- if (id == 0) err_raise(err_SYS,err_PSM_RESET_ON_TEMP, ERR,FALSE);
- resetcontainer(lookupcontainer(id,FALSE,TRUE,TRUE));
-
- TT (psm_H, T_LEAVE);
- }
-
- //------------------------------------------------------------------------------
-
- void sos_Container::squeeze() const
- {
- T_PROC ("sos_Container::squeeze");
- TT (psm_H, T_ENTER; TI(id));
-
- if (id == 0) err_raise(err_SYS,err_PSM_COMMIT_ON_TEMP, ERR,FALSE);
- containerinfo &ci = lookupcontainer(id,FALSE,TRUE);
- commitcontainer(ci);
- squeezecontainer(ci);
- commitcontainer(ci);
-
- TT (psm_H, T_LEAVE);
- }
-
- //------------------------------------------------------------------------------
-
- unsigned sos_Container::allocate(unsigned size) const
- {
-
- T_PROC ("sos_Container::allocate");
- TT (psm_M, T_ENTER; TI(id); TI(size) );
-
- unsigned result;
-
- if (size == 0) err_raise(err_SYS,err_PSM_ALLOC_NULL_BYTES,ERR,FALSE);
- if (id == 0)
- { result = (unsigned) new char [size];
- if (result == 0) err_raise(err_SYS,err_PSM_TEMP_FULL,ERR,FALSE);
- }
- else
- { containerinfo &ci = lookupcontainer(id,FALSE,TRUE);
- if (ci.contpages == 0) // allocate page with table of free blocks
- { allocatepages(ci,1);
- ci.ubfreesize = 0;
- }
- if (size <= MAX_FREEBLOCK_LENGTH)
- { // lookup in table of free blocks, which stands in the first
- // page of the container
- // ( lists of free blocks are only used in :
- // allocate/deallocate, size_of_free_blocks, check_free_lists,
- // (object_exists) )
-
- size=rounded(size);
- result = readint(ci,size);
- if (result != 0) // free block of identical size exists
- writeint(ci,size,readint(ci,result));
- else // try to find block of larger size, starting at size
- { int sz = size + 4; // sz > size
- while (sz <= ci.ubfreesize && readint(ci,sz) == 0)
- sz += 4;
- if (sz <= ci.ubfreesize) // readint(ci,sz) != 0
- { result = readint(ci,sz);
-
- // new first list element
- writeint(ci,sz,readint(ci,result));
-
- // insert rest of bigger block (of length sz - size) in table of
- // free blocks
- writeint(ci,result+size,readint(ci,sz - size));
- writeint(ci,sz - size,result + size);
- }
- else // sz > ci.ubfreesize
- { result = allocatepages(ci,1);
-
- // insert rest of page in table of free blocks
- writeint(ci,result + size,readint(ci,P - size));
- writeint(ci,P - size,result + size);
- ci.ubfreesize = max(ci.ubfreesize, P-size);
- }
- }
- }
- else result = allocatepages(ci, uprounded_pagenumber(size));
- }
-
- TT (psm_M, T_LEAVE; TI(result));
- return result;
- }
-
- //----------------------------------------------------------------------------
-
- void sos_Container::deallocate(sos_Offset o, unsigned size) const
- {
- T_PROC ("sos_Container::deallocate");
- TT (psm_M, T_ENTER; ; TI(id); TI(o); TI(size));
-
- if (size == 0) err_raise(err_SYS,err_PSM_DEALLOC_NULL_BYTES,ERR,FALSE);
- if (id == 0) delete (char*) o;
- else
- if (o < 1024) err_raise(err_SYS,err_PSM_DEALLOCATE_WRONG_OFFSET, ERR,FALSE);
- else
- { containerinfo &ci = lookupcontainer(id,FALSE,TRUE);
- TTN (psm_CHECK_WRITE, check_freelists (ci, o, size));
- if (size <= MAX_FREEBLOCK_LENGTH) //enter in table of free blocks
- { size = rounded(size);
- writeint(ci,o,readint(ci,size)); // link together with list
- writeint(ci,size,o);
- ci.ubfreesize = max(ci.ubfreesize,size);
-
- if (size >= 8) writeint(ci,o+SIZEOF_INT,UNDEF);
- //flag to indicate, that object is deleted:necessary for object_exists()
- }
- else deallocatepages(ci,o/P,uprounded_pagenumber(size));
- }
-
- TT (psm_M, T_LEAVE)
- }
-
- //--------------------------------------------------------------------------
-
- int sos_Container::modified() const
- {
- // return whether sos_Container has been modified since last commit
- // not implemented by status-bit because then in many functions this bit
- // must be set/unset
- // type of returnvalue not of type sos_Bool because psm.h must
- // stand before knl_use.h and forward enum-declaration is not possible
- // container must be opened
-
- T_PROC ("sos_Container::modified");
- TT (psm_H, T_ENTER; TI(id));
-
- if (id == 0) err_raise(err_SYS,err_PSM_MODIFIED_ON_TEMP, ERR,FALSE);
- containerinfo &ci = lookupcontainer(id,FALSE,FALSE);
-
- if (ci.status == WRITEABLE || ci.status == CHECKEDOUT)
- for (int p = 0; p < ci.contpages; p++)
- if (ci.bufferindex[p] != UNDEF && buftable[ci.bufferindex[p]].modified)
- { TT (psm_H, T_LEAVE; TI(TRUE));
- return TRUE; // at least one page is modified
- }
-
- TT (psm_H, T_LEAVE; TI(FALSE));
- return FALSE; // read-only or not opened or not modified
- }
-
- //--------------------------------------------------------------------------
-
- int sos_Container::exists() const
- {
- // returns whether container exists
- // or not (i.e., file is destroyed or container has been destroyed, but the
- // operation has been not yet committed)
-
- T_PROC ("sos_Container::exists");
- TT (psm_H, T_ENTER; TI(id));
-
- int result = FALSE; // modified 24/10/91 (bs)
-
- switch (status())
- {
- case READABLE:
- case WRITEABLE:
- case CHECKEDOUT: result = TRUE;
- break;
-
- case DESTROYED: result = FALSE;
- break;
-
- case UNAVAILABLE: int fd = ::open(containerpath(id),O_RDONLY);
- if (fd != UNDEF)
- { ::close(fd);
- result = TRUE;
- }
- break;
- default: err_raise(err_SYS,err_PSM_EXISTS,ERR,FALSE);
- break;
- };
- TT (psm_H, T_LEAVE; TI(result));
- return result;
- }
-
- //--------------------------------------------------------------------------
-
- int sos_Container::deleted() const
- {
- // returns whether file ,which belongs to container, is deleted or not
-
- T_PROC ("sos_Container::deleted"); TT (psm_H, T_ENTER; TI(id));
- TT (psm_H, T_LEAVE; TI(!exists()));
- return (! exists());
- }
- //--------------------------------------------------------------------------
-
- sos_Existing_status sos_Container::object_exists(sos_Offset o, unsigned size) const
- {
- // returns whether the object exists (perhaps) or not (sure)
- // pre: offset & size belongs to former objects in that container
- // else access outside allocated area is possible
- // (no TRACE inserted because of the many return statements)
-
- int flag;
-
- if (id == 0) return PERHAPS_EXISTING; // temporary container
- if ( rounded(size) < 8) return PERHAPS_EXISTING; // no sos_Object
- if (o < 1024) return NOT_EXISTING; // wrong offset
-
- if (! container_is_open(id)) // container-file(!) not opened
- { // now similar statements as in entercontainer // or not existing
-
- int sw,contpages;
- int fd = ::open(containerpath(id),O_RDONLY);
-
- if (fd == UNDEF) return NOT_EXISTING; // file does not exist
-
- lseek(fd, SWITCH_OFFSET,SEEK_SET); // switch
- ::read(fd,&sw,SIZEOF_INT);
-
- lseek(fd,contpages_offset(sw),SEEK_SET); // number of contpages
- ::read(fd,&contpages,SIZEOF_INT);
-
- if (contpages == 0) return NOT_EXISTING; // container file empty
-
- int contpage = o / P; // logical container page
- if (contpage > contpages) return NOT_EXISTING;
-
- // pagetable_offset in containerfile + page_offset inside pagetable
- lseek(fd, pagetable_offset(contpage,sw) + (contpage%N) * SIZEOF_INT, SEEK_SET);
- ::read(fd,&contpage,SIZEOF_INT); // page in file
-
- if (size <= MAX_FREEBLOCK_LENGTH)
- { if (contpage==UNDEF) return NOT_EXISTING; // WRONG_OFFSET
-
- lseek(fd,fileposition(contpage) + o%P + SIZEOF_INT,SEEK_SET); //offset in file
- // fileposition(contpage) + offset inside of page
- // + SIZEOF_INT (for special bytes (=flagbyte) extra for this function)
- ::read(fd,&flag,SIZEOF_INT);
- return (flag == UNDEF) ? NOT_EXISTING : PERHAPS_EXISTING;
- }
- else // look only at first of (possibly) several pages because of efficiency
- {
- return (contpage == UNDEF) ? NOT_EXISTING : PERHAPS_EXISTING;
- }
- }
- else // container opened
- { containerinfo &ci = lookupcontainer(id,FALSE,FALSE,TRUE);
- if (sos_Container_status(ci.status) == DESTROYED) return NOT_EXISTING;
- if (size <= MAX_FREEBLOCK_LENGTH)
- { // offset 'cannot' be wrong (see:precondition) because never
- // merge free blocks to greater free blocks (pages)
-
- if (uprounded_pagenumber(o + size) > ci.contpages) return NOT_EXISTING;
- flag = readint(ci, o + SIZEOF_INT );
- return (flag == UNDEF) ? NOT_EXISTING : PERHAPS_EXISTING;
- }
- else // if one of the pages is UNDEF or no more existing (>contapges)
- { // => object is NOT_EXISTING
-
- if (o % P != 0) return NOT_EXISTING; // offset must be a multiple of P
- int upper_bound = uprounded_pagenumber(o + size);
- for (int p = o/P; p < upper_bound; p++)
- if ((p > ci.contpages) || (ci.fileindex[p] == UNDEF)) return NOT_EXISTING;
-
- return PERHAPS_EXISTING;
- }
- }
- }
-
- //--------------------------------------------------------------------------
-
- sos_Open_result sos_Container::checkout(sos_Access_mode, sos_Sync_mode) const
- {
- err_raise_not_implemented ("sos_Container::checkout (will be realized by sos_Container::open(CHECKOUT, sync_mode)");
- return UNACCESSIBLE;
- }
-
- //--------------------------------------------------------------------------
-
- unsigned sos_Container::rounded(unsigned size) const
- {
- return (unsigned) (((size+3) /4) *4);
- }
-
- //--------------------------------------------------------------------------
-
- void sos_Container::clear() const
- {
- T_PROC ("sos_Container::clear");
- TT (psm_H, T_ENTER; TI(id));
-
- if (id == 0) err_raise(err_SYS,err_PSM_CLEAR_ON_TEMP, ERR,FALSE);
- containerinfo &ci = lookupcontainer(id,FALSE,TRUE);
- deallocatepages(ci,0,ci.contpages);
- ci.contpages = 0;
-
- TT (psm_H, T_LEAVE);
- }
-
- //--------------------------------------------------------------------------
-
- unsigned sos_Container::occupied() const
- {
- // occupied bytes (data which is referenced from fileindex) in the container file
-
- T_PROC ("sos_Container::occupied");
- TT (psm_H, T_ENTER; TI(id));
-
- if (id == 0) err_raise(err_SYS,err_PSM_EMPTY_ON_TEMP, ERR,FALSE);
- containerinfo &ci = lookupcontainer(id,FALSE,FALSE);
-
- // substract from used_pages all free blocks and first page (table of
- // free blocks)
-
- TT (psm_H, T_LEAVE);
- return (ci.contpages == 0 ? 0 : used_pages(ci)*P - size_of_free_blocks(ci) - P);
- }
-
- //--------------------------------------------------------------------------
-
- void sos_Container::read(sos_Offset o, unsigned size, void* data) const
- {
- T_PROC ("sos_Container::read");
- TT (psm_M, T_ENTER; TI(id); TI(o); TI(size); TP(data));
-
- if (id == 0) bcopy((char*)o,data,size);
- else if (size > 0)
- { containerinfo &ci = lookupcontainer(id,TRUE,FALSE);
- TTN (psm_CHECK_READ, check_freelists (ci, o, size));
-
- char *d = (char*)data;
- int len;
- while (1)
- { int disp = o % P; // displacement in page
-
- if ((len = P-disp) >= size)
- { readfrompage(ci,o/P,disp,size,d);
- break;
- }
- readfrompage(ci,o/P,disp,len,d);
- o += len;
- d += len;
- size -= len; }
- }
-
- TT (psm_M, T_LEAVE);
- }
-
- //--------------------------------------------------------------------------
-
- void sos_Container::write(sos_Offset o, unsigned size, void* data) const
- {
- T_PROC ("sos_Container::write");
- TT (psm_M, T_ENTER; TI(id); TI(o); TI(size); TP(data));
-
- if (id == 0) bcopy(data,(char*)o,size);
- else
- { char *d = (char*)data;
- containerinfo &ci = lookupcontainer(id,FALSE,TRUE);
- TTN (psm_CHECK_WRITE, check_freelists (ci, o, size));
- while (size > 0)
- {
- int disp = o%P; // displacement in page
- int len = min(size, P-disp);
- writetopage(ci,o/P,disp,len,d);
- o += len;
- d += len;
- size -= len;
- }
- }
-
- TT (psm_M, T_LEAVE);
- }
-
- //--------------------------------------------------------------------------
-
- void sos_Container::copy(sos_Offset o1, unsigned size, sos_Container c2,
- sos_Offset o2) const
- {
- T_PROC ("sos_Container::copy");
- TT (psm_M, T_ENTER; TI(id); TI(o1); TI(size); TI((int)c2); TI(o2));
-
- containerinfo *ci1 = containertable,*ci2 = containertable;
- int d1,d2;
- char *a1,*a2;
- if (id != 0) ci1 = &lookupcontainer(id,TRUE,FALSE);
- if (c2.id != 0) ci2 = &lookupcontainer(c2.id,FALSE,TRUE);
- if (o1 > o2) //copy from low to high
- while (size > 0)
- {
- if (id == 0) {d1 = 0; a1 = (char*) o1;}
- else {d1 = o1 % P; a1 = buf[lookuppage(*ci1,o1/P)] + d1; }
- if (c2.id == 0) {d2 = 0; a2 = (char*) o2;}
- else
- { d2 = o2 % P;
- int destbufpage = lookuppage(*ci2,o2/P);
- a2 = buf[destbufpage] + d2;
- buftable[destbufpage].modified = TRUE;
- }
- int len = min(size,min(P-d1,P-d2));
- bcopy(a1,a2,len);
- o1 += len; o2 += len; size -= len;
- }
- else //copy from high to low
- { o1 += size - 1; o2 += size - 1;
- while (size > 0)
- { if (id == 0) {d1 = P; a1 = (char*) o1 + 1;}
- else {d1 = o1%P + 1; a1 = buf[lookuppage(*ci1,o1/P)] + d1; }
- if (c2.id == 0) {d2 = P; a2 = (char*) o2 + 1;}
- else
- {
- d2 = o2%P + 1;
- int destbufpage = lookuppage(*ci2,o2/P);
- a2 = buf[destbufpage] + d2;
- buftable[destbufpage].modified = TRUE;
- }
- int len = min(size,min(d1,d2));
- bcopy(a1-len,a2-len,len);
- o1 -= len; o2 -= len; size -= len;
- }
- }
-
- TT (psm_M, T_LEAVE);
- }
-
- //--------------------------------------------------------------------------
-
- int sos_Container::equal(sos_Offset o1, unsigned size, sos_Container c2,
- sos_Offset o2) const
- {
- T_PROC ("sos_Container::equal");
- TT (psm_M, T_ENTER; TI(id); TI(o1); TI(size); TI((int)c2); TI(o2));
-
- containerinfo *ci1 = containertable,*ci2 = containertable;
- int d1,d2;
- char *a1,*a2;
- if (id == 0) d1 = 0; else ci1 = &lookupcontainer(id,TRUE,FALSE);
- if (c2.id == 0) d2 = 0; else ci2 = &lookupcontainer(c2.id,TRUE,FALSE);
- while (size > 0)
- { if (id == 0) a1 = (char*) o1;
- else {d1 = o1%P; a1 = buf[lookuppage(*ci1,o1/P)] + d1; }
- if (c2.id == 0) a2 = (char*) o2;
- else {d2 = o2%P; a2 = buf[lookuppage(*ci2,o2/P)] + d2; }
- int len = min(size,min(P-d1,P-d2));
- if (bcmp(a1,a2,len) != 0)
- { TT(psm_M, T_LEAVE; TI(FALSE));
- return FALSE;
- }
- o1 += len; o2 += len; size -= len;
- }
-
- TT(psm_M, T_LEAVE; TI(TRUE));
- return TRUE;
- }
-
- //--------------------------------------------------------------------------
-
- int sos_Container::hash_value (sos_Offset o, unsigned size) const
- {
- T_PROC ("sos_Container::hash_value");
- TT (psm_H, T_ENTER; TI(id); TI(o); TI(size));
-
- unsigned u = o + size;
- unsigned l = SIZEOF_INT;
- int result = 0;
- int data;
- for ( ; o < u; o += l)
- { if (l > u - o) { l = u - o; data = 0; } // if size is not a multiple
- // of SIZEOF_INT
- read (o, l, &data);
- result ^= data;
- }
- TT(psm_H, T_LEAVE; TI(result));
- return result;
- }
-
- //--------------------------------------------------------------------------
-
- sos_Object sos_Container::root_object() const
- {
- return sos_Object::make (sos_Typed_id::make (sos_Id::make (*this, ROOT_OFFSET)));
- }
-
- // ********************************************************************
- // functions of class sos_Container_set
- // ********************************************************************
-
- /*
- // copy constructors do not worrk correctly for the gnu-compilers !!!
- sos_Container_set::sos_Container_set(const sos_Container_set& cs)
- {
- size = cs.size;
- n = cs.n;
- s = new int[size];
- int* s2 = cs.s;
- for (int i = 0; i < n; ++i)
- *s++ = *s2++;
- }
-
-
- sos_Container_set& sos_Container_set::operator=(const sos_Container_set& cs)
- {
- size = cs.size;
- n = cs.n;
- s = new int[size];
- int* s2 = cs.s;
- for (int i = 0; i < n; ++i)
- *s++ = *s2++;
-
- // during test , after program termination clobbereed space detected
- // also false results (false container in set)
- // during compilation: warning because of bitwise ...
- // psmtest.c:7: warning: bitwise copy: `sos_Container_set' defines operator=()
- }
-
- */
-
- sos_Container_set::sos_Container_set()
- {
- T_PROC ("sos_Container_set::sos_Container_set");
- TT (psm_H, T_ENTER);
-
- size = 16;
- s = new int[size];
- n = 0;
-
- TT (psm_H, T_LEAVE);
- }
-
- sos_Container_set::~sos_Container_set()
- // { delete [size] s; } // must be inserted again (after presentation)
- {
- }
-
- sos_Container_set& sos_Container_set::operator+=(sos_Container c)
- {
- T_PROC ("sos_Container_set::operator+=");
- TT (psm_H, T_ENTER);
-
- if ( c == TEMP_CONTAINER) err_raise(err_SYS,err_PSM_ADD_WITH_TEMP, ERR,FALSE);
- if (n == size) {extendtable(s,size,2*size); size *= 2; }
- TT (psm_H, T_LEAVE);
- for (int i = 0; i < n; ++i) // multiple appearance of the same container
- if (s[i] == c) // in one set (not bag!) not allowed
- return *this;
- s[n] = (int)c; n++; return *this;
- }
-
- sos_Open_result sos_Container_set::op(int i,const sos_Container_set& rd,const
- sos_Container_set& wr, sos_Sync_mode s)
- {
- if (i < rd.card()) return sos_Container::make(rd.s[i]).open(READING,s);
- else return sos_Container::make(wr.s[i-rd.n]).open(WRITING,s);
- }
-
- void sos_Container_set::cl(int i,const sos_Container_set& rd,const sos_Container_set& wr)
- {
- if (i < rd.card()) sos_Container::make(rd.s[i]).close();
- else sos_Container::make(wr.s[i-rd.n]).close();
- }
-
- sos_Open_result sos_Container_set::open(const sos_Container_set& rd,
- const sos_Container_set& wr, sos_Sync_mode s)
- {
- T_PROC ("sos_Container_set::open");
- TT (psm_H, T_ENTER);
-
- int i = 0;
- while (i < rd.card() + wr.card())
-
- switch (sos_Container_set::op(i,rd,wr,TESTING)) {
- case OPENED: i++; break;
- case UNACCESSIBLE:
- for (int j = 0; j < i; j++) sos_Container_set::cl(j,rd,wr);
- TT (psm_H, T_LEAVE; TI((int)UNACCESSIBLE));
- return UNACCESSIBLE;
- case LOCKED:
- for (int k = 0; k < i; k++) sos_Container_set::cl(k,rd,wr);
- if (s == TESTING)
- { TT (psm_H, T_LEAVE; TI((int)LOCKED));
- return LOCKED;
- }
- switch (sos_Container_set::op(i,rd,wr,WAITING)) {
- case UNACCESSIBLE: TT (psm_H, T_LEAVE; TI((int)UNACCESSIBLE));
- return UNACCESSIBLE;
- case OPENED: sos_Container_set::cl(i,rd,wr); i = 0; } }
-
- TT (psm_H, T_LEAVE; TI((int)OPENED));
- return OPENED;
- }
-
- //--------------------------------------------------------------------------
-
- sos_Container_set& sos_Container_set::open_containers(sos_Container_status stat)
- {
- // returns set of containers openend for WRITING/READING dependent on status
-
- T_PROC ("sos_Container_set::open_containers");
- TT (psm_H, T_ENTER);
-
- sos_Container_set* new_set = new sos_Container_set;
- for (int i = 0; i < C; i++)
- {
- if ((containertable[i].id != UNUSED) && (containertable[i].status == stat))
- (*new_set) += sos_Container::make(containertable[i].id);
- }
- TT (psm_H, T_LEAVE);
- return (*new_set);
- }
-
- //--------------------------------------------------------------------------
-
- sos_Open_result sos_Container_set::open(sos_Access_mode a, sos_Sync_mode s) const
- {
- sos_Container_set empty;
- if (a == READING) return sos_Container_set::open(*this,empty,s);
- else return sos_Container_set::open(empty,*this,s);
- }
-
- //--------------------------------------------------------------------------
-
- void sos_Container_set::close() const
- {
- T_PROC ("sos_Container_set::close"); TT (psm_H, T_ENTER);
- for (int i = 0; i < card(); i++) sos_Container::make(s[i]).close();
- TT(psm_H, T_LEAVE);
- }
-
- //--------------------------------------------------------------------------
-
- void sos_Container_set::commit() const
- {
- T_PROC ("sos_Container_set::commit"); TT (psm_H, T_ENTER);
- for (int i = 0; i < card(); i++) sos_Container::make(s[i]).commit();
- TT(psm_H, T_LEAVE);
- }
-
- //--------------------------------------------------------------------------
-
- void sos_Container_set::reset() const
- {
- T_PROC ("sos_Container_set::reset"); TT (psm_H, T_ENTER);
- for (int i = 0; i < card(); i++) sos_Container::make(s[i]).reset();
- TT(psm_H, T_LEAVE);
- }
-
- // ************ sos_Container_set and sos_Container_cursor *******************
-
- sos_Container_cursor sos_Container_set::open_cursor() const
- {
- // creates a new cursor-object and positions it to the first element
- // if one exists
-
- T_PROC ("sos_Container_set::open_cursor"); TT (psm_L, T_ENTER);
- sos_Container_cursor new_c;
- new_c.idx = (card() > 0) ? 0 : -1 ;
- TT (psm_L, T_LEAVE; TI(new_c.idx));
- return new_c;
- }
-
- //--------------------------------------------------------------------------
-
- void sos_Container_set::close_cursor (sos_Container_cursor &c) const
- {
- T_PROC ("sos_Container_set::close_cursor"); TT (psm_L, T_ENTER);
- c.idx = -1;
- TT (psm_L, T_LEAVE);
- return;
- }
-
- //--------------------------------------------------------------------------
-
- int sos_Container_set::to_succ (sos_Container_cursor& c) const
- {
- // moves cursor one position further and return FALSE, if 'end of
- // set' is reached, else TRUE
- T_PROC ("sos_Container_set::to_succ"); TT (psm_L, T_ENTER);
-
- if ( ++c.idx >= card() )
- { c.idx = -1;
- TT (psm_L, T_LEAVE; TI(FALSE));
- return FALSE;
- }
- else
- { TT (psm_L, T_LEAVE; TI(TRUE));
- return TRUE;
- }
- }
-
- //--------------------------------------------------------------------------
-
- int sos_Container_set::is_valid (sos_Container_cursor c) const
- {
- T_PROC ("sos_Container_set::is_valid"); TT (psm_L, T_ENTER);
- TT (psm_L, T_LEAVE);
- return (c.idx >= 0 && c.idx < card());
- }
-
- //--------------------------------------------------------------------------
-
- sos_Container sos_Container_set::get (sos_Container_cursor c) const
- {
- T_PROC ("sos_Container_set::get"); TT (psm_L, T_ENTER);
- if ( ! this->is_valid(c)) err_raise(err_SYS,err_PSM_INVALID_CURSOR, ERR,FALSE);
- TT (psm_L, T_LEAVE);
- return sos_Container::make(s[c.idx]);
- }
-
- //----------------------------------------------------------------------------
- /* TRACE generates for the functions of class sos_Container and sos_Container_set
- (and for function lock()) the following output:
-
- T_ENTER: name of function, container id and all arguments of the function
- T_LEAVE: name of function and return argument
-
- exceptions for T_LEAVE
- - no output of return argument : status, occupied, lock, get, is_valid
- exceptions for T_ENTER
- - no output of id : create
-
- exception for TRACE at all: object_exists
- */
- //----------------------------------------------------------------------------
- /*
-
- //--------- to do for release SOS3-2 ----------------------------------
-
- - SOSBUFFERSIZE - wo dokumentieren, wo ist SOS_MONITOR dokumentiert ???
-
- --------- POSTPONED -------------
-
- - destruktor fuer contaiener_set => .... Implementierung von container_set wie
- bei smg_string
-
- - in object_exists Funktion readint_from_file herausfaktorisieren
-
- EFFIZIENZTEST FUER INLINE ... (einmal fast nichts, einmal fast alle
- hilfsfkt. inline)
- - moeglichst viele Hilfsfunktonen inline deklarieren => nur fuer die
- Hilfsfunktionen wird einmal Code angelegt bzw. so hauefig, we sie in den
- Interfacefunktionen vorkommen. Wie oft die Schnittstellenfunktionen aufgerufen
- werden, ist voellig egal, dort steht ja nur ein Funktionsaufruf.
-
- - effizienzv improvement for read() ... with no use of bcopy
- (in read() ... replace bcopy, if size <=16, ...)
-
- - compress
-
- sos_Container als sos_Objects :
- ? Klasse als Schnittstelle darueberlegen
- ? sind containersets richtig implementiert :
- falls der Anwender unterprogramm mit paramater (nicht &) uerbergibt wird
- beim ruecksprung cnt_set zerstoert und wenn dem Anwender set
- uebergeben wird und dieser sein Programm beendet (macht nichts. da set nur
- im hauptspeicher ?!
-
- wie ist dies in SOS realisiert: referenzcounter, der bei 'copy' mitzaehlt
- wieviele referenzen auf dieses aggragate existieren und erst bei 0 dieses
- loescht
-
- -------- DONE ---------
-
- - globale unix-variable fuer sosbuffersize
- - Benutzer kann sich selbst groesse waeheln
- - Zeitmessungen moeglich
-
- - interne Funktionen verbessern bzw. erzeugen
- z.B. container_exists...
-
- - sos_Access_mode/sos_CONtainer_status klar trennen .status/ c.status() / ...
-
- - MAX_FREEBLOPCVKLENGTH = P-8 ersetzen durch P-4, size oder rounded(size) <=
- MAX... ist egal ...
-
- - sos-gsh als test vom psm durchfuehren
-
- - checkout-Funktionsheader nicht direkjt loeschen, sondern durch Fehlermeldung
- " not implemented ..." ersetzzen" und in keinem Fall in der Manpage
- erwaaehnen
-
- - manpages aktualisieren und an vielen Stellen ausfuhrlivcher beschreiben
- - neue TRC-Switches psm_check_erad/write in Manpage beschreiben
-
- - Destroy: siehe File "Destroy"
-
- - Effizienz fuer sehr grosse Container ?
- Da das Laden der seitentabelle viel Zeit kostet (fuer groose Container) und
- auch das Zurueckschreiben bei commit, koenen auch kleine Aenderungen am
- Containerinhalt viel Zeit kosten (falls Container gross).
- Kann man dies verbessern?
-
- Beim Zurueckschreiben: nicht nur ein Switch fuer alle Teile der Seitentabelle
- verwalten, sondern fuer jeden Teil ein extra-Switch und ein Gesamt-Switch.
- Dadurch mueste man nur noch ein Byte (oder 4) statt 1024 Byte schreiben, falls
- sich der zugehoerige Teil der seitentabelle nicht geaendert hat. Mehraufwand
- waehren ein paar Abfragen ( ? und pruefen, welche Teile der Seitentabelle von
- den Aederungen betroffen sind ?). Lohnt sich sicher nur fuer sehr grosse
- Container, die daher nicht zu oft geoeefnet und geschlossen werden sollten.
-
- Beim Oeffnen des Containers: Die Seitentabelle musste "lazy" geladen weren,
- dass heisst die betreffenden Teile wereen nur dann in den Hauptspeicher
- geladen, wenn erforderlich. => viel komplizierter unf lohnt sich wirklich nur
- fuer sehr grosse Files (koennte man durch die Laenge der Seitentabelle anfangs
- abfragen und vielleicht als parameter beim oeffnen mitgeben: normal_open
- or 'open_with_lazy_changes"
-
-
-
- */
- //-----------------------------------------------------------------------------
- // end of psm.c
- //-----------------------------------------------------------------------------
-
-